use std::any::Any;

use graphics::{Frame, Size};

use crate::contexts::{EventCtx, LayoutCtx, LifeCycleCtx, PaintCtx};
use crate::event::{Event, LifeCycle};

pub trait Widget {
    fn event(&mut self, cx: &mut EventCtx, event: &Event);
    fn paint(&mut self, cx: &mut PaintCtx, g: &mut Frame);
    fn layout(&mut self, cx: &mut LayoutCtx) -> Size;
    fn lifecycle(&mut self, cx: &mut LifeCycleCtx, event: &LifeCycle);
}

impl Widget for Box<dyn Widget> {
    fn event(&mut self, cx: &mut EventCtx, event: &Event) {
        self.as_mut().event(cx, event)
    }

    fn paint(&mut self, cx: &mut PaintCtx, g: &mut Frame) {
        self.as_mut().paint(cx, g)
    }

    fn layout(&mut self, cx: &mut LayoutCtx) -> Size {
        self.as_mut().layout(cx)
    }

    fn lifecycle(&mut self, cx: &mut LifeCycleCtx, event: &LifeCycle) {
        self.as_mut().lifecycle(cx, event)
    }
}

pub trait AnyWidget: Widget {
    fn as_any(&self) -> &dyn Any;
    fn as_any_mut(&mut self) -> &mut dyn Any;
    fn type_name(&self) -> &'static str;
}

impl<W: Widget + 'static> AnyWidget for W {
    fn as_any(&self) -> &dyn Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }

    fn type_name(&self) -> &'static str {
        std::any::type_name::<Self>()
    }
}
